import decimal
import json

from flask import request, g

from application import app, db
from common.libs.CartService.CartService import CartService
from common.libs.PayService.PayService import PayService
from common.libs.Restful import Restful
from common.libs.UrlManager import UrlManager
from common.libs.WechatService.WechatService import WeChatService
from common.models.foods.Food import Food
from common.models.members.OAuthMemberBind import OauthMemberBind
from common.models.order.PayOrder import PayOrder
from . import api_route

@api_route.route('/order/info/', methods=['POST'])
def order():
    req = request.values
    params_goods = req['goods'] if 'goods' in req else None
    member_info = g.member_info
    params_goods_list = []
    if params_goods:
        params_goods_list = json.loads(params_goods)
    food_dic = {}
    for item in params_goods_list:
        food_dic[item['id']] = item['number']
    food_ids = food_dic.keys()
    food_list = Food.query.filter(Food.id.in_(food_ids)).all()
    data_food_list = []
    yun_price = pay_price = decimal.Decimal(0.00)
    if food_list:
        for item in food_list:
            tmp_data = {
                'id': item.id,
                'name': item.name,
                'price': str(item.price),
                'pic_url': UrlManager.buildImageUrl(item.main_image),
                'number': food_dic[item.id],
            }
            pay_price = pay_price + item.price * int(food_dic[item.id])
            data_food_list.append(tmp_data)
    default_address = {
        'name': 'sdf',
        'mobile': 'sdfsf',
        'address': 'sdfsf'
    }
    data = {
        'address': default_address,
        'food_list': data_food_list,
        'pay_price': str(pay_price),
        'yun_price': str(yun_price),
        'total_price': str(pay_price + yun_price)
    }
    return Restful.success(data=data)


@api_route.route('/order/create/', methods=['POST'])
def create():
    req = request.values
    type = req['type'] if req['type'] else ''
    note = req['note'] if req['note'] else ''
    params_goods = req['goods'] if 'goods' in req else None

    items = []
    if params_goods:
        items = json.loads(params_goods)
    if len(items) < 1:
        return Restful.format_error(msg='下单失败，没有选择商品')

    member_info = g.member_info
    target = PayService()
    resp = target.createOrder(member_info.id, items=items, params={'note': note})
    if resp.status == '200' and type == 'cart':
        # 下单成功后将购物车对应的数据删除
        CartService.deleteItem(member_id=member_info.id, items=items)
    return resp


@api_route.route('/order/orderpay/', methods=['POST'])
def orderpay():
    order_sn = request.values.get('order_sn') if 'order_sn' in request.values else ''
    if not order_sn:
        return Restful.param_error(msg='缺少参数')
    order_info = PayOrder.query.filter_by(order_sn=order_sn).first()
    if not order_info:
        return Restful.param_error(msg='系统繁忙，请稍后重试')
    member_info = g.member_info
    oauth_bind_info = OauthMemberBind.query.filter_by(member_id=member_info.id).first()
    if not oauth_bind_info:
        return Restful.param_error(msg='系统繁忙，请稍后重试')

    config_mina = app.config['MINA_APP']
    notify_url = app.config['APP']['domain'] + config_mina['callback_url']

    target_wechat = WeChatService(config_mina['paykey'])

    '''
    appid           小程序id
    mch_id          商户号
    body            商品描述
    out_trade_no    商户订单号，保证唯一，从订单信息中取出
    total_fee       支付总价 单位是分
    notify_url      支付回调方法 通知地址
    trade_type      交易类型 小程序是JSAPI
    openid          用户标识
    nonce_str       随机字符串
    '''
    data = {
        'appid': config_mina['appid'], #小程序ID
        'mch_id': config_mina['mch_id'],
        'body': '订餐',
        'out_trade_no': order_info.order_sn,
        'total_fee': int(order_info.total_price * 100),
        'notify_url': notify_url,
        'trade_type': 'JSAPI',
        'openid': oauth_bind_info.openid,
        'nonce_str': target_wechat.get_nonce_str()
    }

    # 调微信支付统一下单接口
    pay_info = target_wechat.get_pay_info(data)

    # 保存prepay_id 为了后面发模板消息
    if not pay_info:
        return Restful.param_error(msg='支付失败，请重试')
    pay_info.prepay_id = pay_info['prepay_id']
    db.session.commit()

    return Restful.success(data={'pay_info': pay_info})


# 微信支付回调接口，此接口需要在pay_data中定义为nogify_url传给微信，如果支付完成无论失败，都会有xml数据以request.data的形式传给此接口
@api_route.route('/order/callback', methods=['POST'])
def orderCallback():
    result_data = {
        'return_code': 'SUCCESS',
        'return_msg': 'OK'
    }

    header = {'Content-Type': 'application/xml'}

    config_mina = app.config['MINA_APP']
    target_wechat = WeChatService(merchant_key=config_mina['paykey'])
    callback_data = target_wechat.xml_to_dict(request.data)
    sign = callback_data['sign']
    callback_data.pop('sign')
    gene_sign = target_wechat.create_sign(callback_data)
    # 将微信传给我们的xml转成dict取出sign，然后再把sign删除后进行和提交sign时一样的加密方法加密，比对两个sign是否一致，如果一致则说明使我们发送的支付，如果不是再构造一个失败的xml返回给微信
    if sign != gene_sign:
        result_data['return_code'] = result_data['return_msg'] = 'FAIL'
        return target_wechat.dict_to_xml(result_data), header

    order_sn = callback_data['out_trade_no']
    pay_order_info = PayOrder.query.filter_by(order_sn=order_sn).first()

    # 如果根据out_trade_no订单唯一标识没有在本地数据库查到对应订单信息，则直接返回FAIL给微信
    if not pay_order_info:
        result_data['return_code'] = result_data['return_msg'] = 'FAIL'
        return target_wechat.dict_to_xml(result_data), header

    # 如果查出的订单总价和微信返的订单总价不一致，则直接返回FAIL给微信
    if int((pay_order_info.total_price * 100) != callback_data['total_fee']):
        result_data['return_code'] = result_data['return_msg'] = 'FAIL'
        return target_wechat.dict_to_xml(result_data), header

    # 如果订单已经是支付成功了，则直接返回SUCCESS给微信
    if pay_order_info.status == 1:
        return target_wechat.dict_to_xml(result_data), header

    target_pay = PayService()
    # 将微信的订单号记录到本地数据库transaction_id
    target_pay.orderSuccess(pay_order_id=pay_order_info.id, params={'pay_sn':callback_data['transaction_id']})

    target_pay.addPayCallbackData(pay_order_id=pay_order_info.id, data=request.data)
    # 将微信结果放入记录表
    return target_wechat.dict_to_xml(result_data), header